package org.glutenberg.dao;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.Vector;

import org.glutenberg.util.RandomAccessStreamReader;
import org.glutenberg.util.StringComparator;
import org.glutenberg.util.StringUtils;
import org.glutenberg.util.TreeSet;

public class ReverseIndex {
	
	private AlphabeticIndex alphabeticalIndex;
	private RandomAccessStreamReader reader;

	public ReverseIndex(RandomAccessStreamReader reader, AlphabeticIndex alphabeticIndex){
		this.alphabeticalIndex = alphabeticIndex;
		this.reader = reader;
	}
	
	public Vector getProductIndexes(Vector words) throws UnsupportedEncodingException, IOException{
		return this.getProductIndexes(words, true);
	}
	
	public Vector getProductIndexes(Vector words, boolean prepareWords) throws UnsupportedEncodingException, IOException{
		if(words.size()==0) return new Vector();
		if(prepareWords){
			words = prepareWords(words);
		}
		TreeSet directIndexes=null, listIndexes=new TreeSet();
		directIndexes = this.getDirectAndListIndexes(words, directIndexes, listIndexes);
		if(directIndexes!=null && directIndexes.size()==0) return new Vector();		
		if(listIndexes.size()>0){
			directIndexes = this.addListIndexes(listIndexes, directIndexes);
		}
		Vector ret = new Vector();
		if(directIndexes!=null){
			for(Enumeration i = directIndexes.elements();i.hasMoreElements();){
				IndexRecord record = (IndexRecord)i.nextElement();
				ret.addElement(new Long(record.getIndex()));
			}
		}
		return ret;
	}
	
	public static Vector prepareWords(Vector words){
		TreeSet set = new TreeSet(new StringComparator());
		for(int i=0;i<words.size();i++){
			String word = (String) words.elementAt(i);
			if(word!=null){
				word = word.trim().toLowerCase();
				if(word.length()>2){
					set.add(word);
				}
			}
		}
		Vector ret = new Vector();
		for(Enumeration e=set.elements();e.hasMoreElements();){
			String s = (String)e.nextElement();
			ret.addElement(s);
		}
		return ret;
	}
	
	private TreeSet getDirectAndListIndexes(Vector words, TreeSet directIndexes, TreeSet listIndexes) throws IOException{
		Vector records = this.alphabeticalIndex.getIndexes(words);
		if(records.size()!=words.size()) return new TreeSet();
		
		for(int i=0;i<records.size();i++){
			TreeSet directIndexes1 = new TreeSet();
			IndexRecord record = (IndexRecord) records.elementAt(i);
			if(record==null) return directIndexes1;
			else {
				if(record.isListIndex()) listIndexes.add(record);
				else directIndexes1.add(record);
				if(!record.isListIndex()){
					if(directIndexes==null){
						directIndexes = directIndexes1;
					} else {
						directIndexes = directIndexes1.intersection(directIndexes);
					}
				}
			}		
		}
		return directIndexes;
	}
	
	private TreeSet addListIndexes(TreeSet listIndexes, TreeSet directIndexes) throws IOException{
		Enumeration i = listIndexes.elements();
		while(i.hasMoreElements()){
			TreeSet directIndexes1 = new TreeSet();
			IndexRecord record = (IndexRecord)i.nextElement();
			this.reader.seek(this.alphabeticalIndex.getEndIndex() + record.getIndex());
			StringBuffer buffer = new StringBuffer();
			char c  = (char)reader.read();
			while(c>=0 && c!='\n'){
				if(c==','){
					IndexRecord index = new IndexRecord(Long.parseLong(buffer.toString()));
					directIndexes1.add(index);
					buffer.setLength(0);
				} else buffer.append(c);
				c  = (char)reader.read();
			}
			System.out.println(Runtime.getRuntime().freeMemory());
			if(c=='\n'){
				IndexRecord index = new IndexRecord(Long.parseLong(buffer.toString()));
				directIndexes1.add(index);
			}
			if(directIndexes==null) directIndexes = directIndexes1;
			else directIndexes = directIndexes.intersection(directIndexes1);
			if(directIndexes!=null && directIndexes.size()==0) return new TreeSet();
		}
		return directIndexes;
	}
	
	public long getEndIndex(){
		return this.alphabeticalIndex.getReverseIndexEnd();
	}
	
}
